home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevpdfu.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  26.4 KB  |  970 lines

  1. /* Copyright (C) 1999, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevpdfu.c,v 1.12 2000/09/19 19:00:17 lpd Exp $ */
  20. /* Output utilities for PDF-writing driver */
  21. #include "memory_.h"
  22. #include "jpeglib_.h"        /* for sdct.h */
  23. #include "string_.h"
  24. #include "gx.h"
  25. #include "gserrors.h"
  26. #include "gscdefs.h"
  27. #include "gsdsrc.h"
  28. #include "gsfunc.h"
  29. #include "gdevpdfx.h"
  30. #include "gdevpdfo.h"
  31. #include "scanchar.h"
  32. #include "strimpl.h"
  33. #include "sa85x.h"
  34. #include "scfx.h"
  35. #include "sdct.h"
  36. #include "slzwx.h"
  37. #include "spngpx.h"
  38. #include "srlx.h"
  39. #include "sstring.h"
  40. #include "szlibx.h"
  41.  
  42. /* Define the size of internal stream buffers. */
  43. /* (This is not a limitation, it only affects performance.) */
  44. #define sbuf_size 512
  45.  
  46. /* Optionally substitute other filters for FlateEncode for debugging. */
  47. #if 1
  48. #  define compression_filter_name "FlateDecode"
  49. #  define compression_filter_template s_zlibE_template
  50. #  define compression_filter_state stream_zlib_state
  51. #else
  52. #  include "slzwx.h"
  53. #  define compression_filter_name "LZWDecode"
  54. #  define compression_filter_template s_LZWE_template
  55. #  define compression_filter_state stream_LZW_state
  56. #endif
  57.  
  58. /* Import procedures for writing filter parameters. */
  59. extern stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state);
  60. extern stream_state_proc_get_params(s_CF_get_params, stream_CF_state);
  61.  
  62. #define CHECK(expr)\
  63.   BEGIN if ((code = (expr)) < 0) return code; END
  64.  
  65. /* GC descriptors */
  66. extern_st(st_pdf_font);
  67. extern_st(st_pdf_char_proc);
  68. extern_st(st_pdf_font_descriptor);
  69. public_st_pdf_resource();
  70. private_st_pdf_x_object();
  71.  
  72. /* ---------------- Utilities ---------------- */
  73.  
  74. /* ------ Document ------ */
  75.  
  76. /* Open the document if necessary. */
  77. void
  78. pdf_open_document(gx_device_pdf * pdev)
  79. {
  80.     if (!is_in_page(pdev) && pdf_stell(pdev) == 0) {
  81.     stream *s = pdev->strm;
  82.     int level = (int)(pdev->CompatibilityLevel * 10 + 0.5);
  83.  
  84.     pprintd2(s, "%%PDF-%d.%d\n", level / 10, level % 10);
  85.     pdev->binary_ok = !pdev->params.ASCII85EncodePages;
  86.     if (pdev->binary_ok)
  87.         pputs(s, "%\307\354\217\242\n");
  88.     }
  89.     /*
  90.      * Determine the compression method.  Currently this does nothing.
  91.      * It also isn't clear whether the compression method can now be
  92.      * changed in the course of the document.
  93.      *
  94.      * The following algorithm is per an update to TN # 5151 by
  95.      * Adobe Developer Support.
  96.      */
  97.     if (!pdev->params.CompressPages)
  98.     pdev->compression = pdf_compress_none;
  99.     else if (pdev->CompatibilityLevel < 1.2)
  100.     pdev->compression = pdf_compress_LZW;
  101.     else if (pdev->params.UseFlateCompression)
  102.     pdev->compression = pdf_compress_Flate;
  103.     else
  104.     pdev->compression = pdf_compress_LZW;
  105. }
  106.  
  107. /* ------ Objects ------ */
  108.  
  109. /* Allocate an object ID. */
  110. private long
  111. pdf_next_id(gx_device_pdf * pdev)
  112. {
  113.     return (pdev->next_id)++;
  114. }
  115.  
  116. /*
  117.  * Return the current position in the output.  Note that this may be in the
  118.  * main output file, the asides file, or the pictures file.  If the current
  119.  * file is the pictures file, positions returned by pdf_stell must only be
  120.  * used locally (for computing lengths or patching), since there is no way
  121.  * to map them later to the eventual position in the output file.
  122.  */
  123. long
  124. pdf_stell(gx_device_pdf * pdev)
  125. {
  126.     stream *s = pdev->strm;
  127.     long pos = stell(s);
  128.  
  129.     if (s == pdev->asides.strm)
  130.     pos += ASIDES_BASE_POSITION;
  131.     return pos;
  132. }
  133.  
  134. /* Allocate an ID for a future object. */
  135. long
  136. pdf_obj_ref(gx_device_pdf * pdev)
  137. {
  138.     long id = pdf_next_id(pdev);
  139.     long pos = pdf_stell(pdev);
  140.  
  141.     fwrite(&pos, sizeof(pos), 1, pdev->xref.file);
  142.     return id;
  143. }
  144.  
  145. /* Begin an object, optionally allocating an ID. */
  146. long
  147. pdf_open_obj(gx_device_pdf * pdev, long id)
  148. {
  149.     stream *s = pdev->strm;
  150.  
  151.     if (id <= 0) {
  152.     id = pdf_obj_ref(pdev);
  153.     } else {
  154.     long pos = pdf_stell(pdev);
  155.     FILE *tfile = pdev->xref.file;
  156.     long tpos = ftell(tfile);
  157.  
  158.     fseek(tfile, (id - pdev->FirstObjectNumber) * sizeof(pos),
  159.           SEEK_SET);
  160.     fwrite(&pos, sizeof(pos), 1, tfile);
  161.     fseek(tfile, tpos, SEEK_SET);
  162.     }
  163.     pprintld1(s, "%ld 0 obj\n", id);
  164.     return id;
  165. }
  166. long
  167. pdf_begin_obj(gx_device_pdf * pdev)
  168. {
  169.     return pdf_open_obj(pdev, 0L);
  170. }
  171.  
  172. /* End an object. */
  173. int
  174. pdf_end_obj(gx_device_pdf * pdev)
  175. {
  176.     pputs(pdev->strm, "endobj\n");
  177.     return 0;
  178. }
  179.  
  180. /* ------ Page contents ------ */
  181.  
  182. /* Handle transitions between contexts. */
  183. private int
  184.     none_to_stream(P1(gx_device_pdf *)), stream_to_text(P1(gx_device_pdf *)),
  185.     string_to_text(P1(gx_device_pdf *)), text_to_stream(P1(gx_device_pdf *)),
  186.     stream_to_none(P1(gx_device_pdf *));
  187. typedef int (*context_proc) (P1(gx_device_pdf *));
  188. private const context_proc context_procs[4][4] =
  189. {
  190.     {0, none_to_stream, none_to_stream, none_to_stream},
  191.     {stream_to_none, 0, stream_to_text, stream_to_text},
  192.     {text_to_stream, text_to_stream, 0, 0},
  193.     {string_to_text, string_to_text, string_to_text, 0}
  194. };
  195.  
  196. /* Enter stream context. */
  197. private int
  198. none_to_stream(gx_device_pdf * pdev)
  199. {
  200.     stream *s;
  201.  
  202.     if (pdev->contents_id != 0)
  203.     return_error(gs_error_Fatal);    /* only 1 contents per page */
  204.     pdev->contents_id = pdf_begin_obj(pdev);
  205.     pdev->contents_length_id = pdf_obj_ref(pdev);
  206.     s = pdev->strm;
  207.     pprintld1(s, "<</Length %ld 0 R", pdev->contents_length_id);
  208.     if (pdev->compression == pdf_compress_Flate)
  209.     pprints1(s, "/Filter /%s", compression_filter_name);
  210.     pputs(s, ">>\nstream\n");
  211.     pdev->contents_pos = pdf_stell(pdev);
  212.     if (pdev->compression == pdf_compress_Flate) {    /* Set up the Flate filter. */
  213.     const stream_template *template = &compression_filter_template;
  214.     stream *es = s_alloc(pdev->pdf_memory, "PDF compression stream");
  215.     byte *buf = gs_alloc_bytes(pdev->pdf_memory, sbuf_size,
  216.                    "PDF compression buffer");
  217.     compression_filter_state *st =
  218.         gs_alloc_struct(pdev->pdf_memory, compression_filter_state,
  219.                 template->stype, "PDF compression state");
  220.  
  221.     if (es == 0 || st == 0 || buf == 0)
  222.         return_error(gs_error_VMerror);
  223.     s_std_init(es, buf, sbuf_size, &s_filter_write_procs,
  224.            s_mode_write);
  225.     st->memory = pdev->pdf_memory;
  226.     st->template = template;
  227.     es->state = (stream_state *) st;
  228.     es->procs.process = template->process;
  229.     es->strm = s;
  230.     (*template->set_defaults) ((stream_state *) st);
  231.     (*template->init) ((stream_state *) st);
  232.     pdev->strm = s = es;
  233.     }
  234.     /* Scale the coordinate system. */
  235.     pprintg2(s, "%g 0 0 %g 0 0 cm\n",
  236.          72.0 / pdev->HWResolution[0], 72.0 / pdev->HWResolution[1]);
  237.     if (pdev->CompatibilityLevel >= 1.3) {
  238.     /* Set the default rendering intent. */
  239.     if (pdev->params.DefaultRenderingIntent != ri_Default) {
  240.         static const char *const ri_names[] = { psdf_ri_names };
  241.  
  242.         pprints1(s, "/%s ri\n",
  243.              ri_names[(int)pdev->params.DefaultRenderingIntent]);
  244.     }
  245.     }
  246.     /* Do a level of gsave for the clipping path. */
  247.     pputs(s, "q\n");
  248.     return PDF_IN_STREAM;
  249. }
  250. /* Enter text context from stream context. */
  251. private int
  252. stream_to_text(gx_device_pdf * pdev)
  253. {
  254.     /*
  255.      * Bizarrely enough, Acrobat Reader cares how the final font size is
  256.      * obtained -- the CTM (cm), text matrix (Tm), and font size (Tf)
  257.      * are *not* all equivalent.  In particular, it seems to use the
  258.      * product of the text matrix and font size to decide how to
  259.      * anti-alias characters.  Therefore, we have to temporarily patch
  260.      * the CTM so that the scale factors are unity.  What a nuisance!
  261.      */
  262.     pprintg2(pdev->strm, "q %g 0 0 %g 0 0 cm BT\n",
  263.          pdev->HWResolution[0] / 72.0, pdev->HWResolution[1] / 72.0);
  264.     pdev->procsets |= Text;
  265.     gs_make_identity(&pdev->text.matrix);
  266.     pdev->text.line_start.x = pdev->text.line_start.y = 0;
  267.     pdev->text.buffer_count = 0;
  268.     return PDF_IN_TEXT;
  269. }
  270. /* Exit string context to text context. */
  271. private int
  272. string_to_text(gx_device_pdf * pdev)
  273. {
  274.     pdf_put_string(pdev, pdev->text.buffer, pdev->text.buffer_count);
  275.     pputs(pdev->strm, (pdev->text.use_leading ? "'\n" : "Tj\n"));
  276.     pdev->text.use_leading = false;
  277.     pdev->text.buffer_count = 0;
  278.     return PDF_IN_TEXT;
  279. }
  280. /* Exit text context to stream context. */
  281. private int
  282. text_to_stream(gx_device_pdf * pdev)
  283. {
  284.     pputs(pdev->strm, "ET Q\n");
  285.     pdf_reset_text(pdev);    /* because of Q */
  286.     return PDF_IN_STREAM;
  287. }
  288. /* Exit stream context. */
  289. private int
  290. stream_to_none(gx_device_pdf * pdev)
  291. {
  292.     stream *s = pdev->strm;
  293.     long length;
  294.  
  295.     if (pdev->compression == pdf_compress_Flate) {    /* Terminate the Flate filter. */
  296.     stream *fs = s->strm;
  297.  
  298.     sclose(s);
  299.     gs_free_object(pdev->pdf_memory, s->cbuf, "zlib buffer");
  300.     gs_free_object(pdev->pdf_memory, s, "zlib stream");
  301.     pdev->strm = s = fs;
  302.     }
  303.     length = pdf_stell(pdev) - pdev->contents_pos;
  304.     pputs(s, "endstream\n");
  305.     pdf_end_obj(pdev);
  306.     pdf_open_obj(pdev, pdev->contents_length_id);
  307.     pprintld1(s, "%ld\n", length);
  308.     pdf_end_obj(pdev);
  309.     return PDF_IN_NONE;
  310. }
  311.  
  312. /* Begin a page contents part. */
  313. int
  314. pdf_open_contents(gx_device_pdf * pdev, pdf_context_t context)
  315. {
  316.     int (*proc) (P1(gx_device_pdf *));
  317.  
  318.     while ((proc = context_procs[pdev->context][context]) != 0) {
  319.     int code = (*proc) (pdev);
  320.  
  321.     if (code < 0)
  322.         return code;
  323.     pdev->context = (pdf_context_t) code;
  324.     }
  325.     pdev->context = context;
  326.     return 0;
  327. }
  328.  
  329. /* Close the current contents part if we are in one. */
  330. int
  331. pdf_close_contents(gx_device_pdf * pdev, bool last)
  332. {
  333.     if (pdev->context == PDF_IN_NONE)
  334.     return 0;
  335.     if (last) {            /* Exit from the clipping path gsave. */
  336.     pdf_open_contents(pdev, PDF_IN_STREAM);
  337.     pputs(pdev->strm, "Q\n");
  338.     pdev->text.font = 0;
  339.     }
  340.     return pdf_open_contents(pdev, PDF_IN_NONE);
  341. }
  342.  
  343. /* ------ Resources et al ------ */
  344.  
  345. /* Define the allocator descriptors for the resource types. */
  346. private const char *const resource_names[] = {
  347.     pdf_resource_type_names
  348. };
  349. private const gs_memory_struct_type_t *const resource_structs[] = {
  350.     pdf_resource_type_structs
  351. };
  352.  
  353. /* Find a resource of a given type by gs_id. */
  354. pdf_resource_t *
  355. pdf_find_resource_by_gs_id(gx_device_pdf * pdev, pdf_resource_type_t rtype,
  356.                gs_id rid)
  357. {
  358.     pdf_resource_t **pchain = PDF_RESOURCE_CHAIN(pdev, rtype, rid);
  359.     pdf_resource_t **pprev = pchain;
  360.     pdf_resource_t *pres;
  361.  
  362.     for (; (pres = *pprev) != 0; pprev = &pres->next)
  363.     if (pres->rid == rid) {
  364.         if (pprev != pchain) {
  365.         *pprev = pres->next;
  366.         pres->next = *pchain;
  367.         *pchain = pres;
  368.         }
  369.         return pres;
  370.     }
  371.     return 0;
  372. }
  373.  
  374. /* Begin an object logically separate from the contents. */
  375. long
  376. pdf_open_separate(gx_device_pdf * pdev, long id)
  377. {
  378.     pdf_open_document(pdev);
  379.     pdev->asides.save_strm = pdev->strm;
  380.     pdev->strm = pdev->asides.strm;
  381.     return pdf_open_obj(pdev, id);
  382. }
  383. long
  384. pdf_begin_separate(gx_device_pdf * pdev)
  385. {
  386.     return pdf_open_separate(pdev, 0L);
  387. }
  388.  
  389. /* Begin an aside (resource, annotation, ...). */
  390. private int
  391. pdf_alloc_aside(gx_device_pdf * pdev, pdf_resource_t ** plist,
  392.         const gs_memory_struct_type_t * pst, pdf_resource_t **ppres,
  393.         long id)
  394. {
  395.     pdf_resource_t *pres;
  396.     cos_object_t *object;
  397.  
  398.     if (pst == NULL)
  399.     pst = &st_pdf_resource;
  400.     pres = gs_alloc_struct(pdev->pdf_memory, pdf_resource_t, pst,
  401.                "pdf_alloc_aside(resource)");
  402.     object = cos_object_alloc(pdev, "pdf_alloc_aside(object)");
  403.     if (pres == 0 || object == 0) {
  404.     return_error(gs_error_VMerror);
  405.     }
  406.     object->id = (id < 0 ? -1L : id == 0 ? pdf_obj_ref(pdev) : id);
  407.     pres->next = *plist;
  408.     *plist = pres;
  409.     pres->prev = pdev->last_resource;
  410.     pdev->last_resource = pres;
  411.     pres->named = false;
  412.     pres->used_on_page = true;
  413.     pres->object = object;
  414.     *ppres = pres;
  415.     return 0;
  416. }
  417. int
  418. pdf_begin_aside(gx_device_pdf * pdev, pdf_resource_t ** plist,
  419.         const gs_memory_struct_type_t * pst, pdf_resource_t ** ppres)
  420. {
  421.     long id = pdf_begin_separate(pdev);
  422.  
  423.     if (id < 0)
  424.     return (int)id;
  425.     return pdf_alloc_aside(pdev, plist, pst, ppres, id);
  426. }
  427.  
  428. /* Begin a resource of a given type. */
  429. int
  430. pdf_begin_resource_body(gx_device_pdf * pdev, pdf_resource_type_t rtype,
  431.             gs_id rid, pdf_resource_t ** ppres)
  432. {
  433.     int code = pdf_begin_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, rid),
  434.                    resource_structs[rtype], ppres);
  435.  
  436.     if (code >= 0)
  437.     (*ppres)->rid = rid;
  438.     return code;
  439. }
  440. int
  441. pdf_begin_resource(gx_device_pdf * pdev, pdf_resource_type_t rtype, gs_id rid,
  442.            pdf_resource_t ** ppres)
  443. {
  444.     int code = pdf_begin_resource_body(pdev, rtype, rid, ppres);
  445.  
  446.     if (code >= 0 && resource_names[rtype] != 0) {
  447.     stream *s = pdev->strm;
  448.  
  449.     pprints1(s, "<</Type/%s", resource_names[rtype]);
  450.     pprintld1(s, "/Name/R%ld", (*ppres)->object->id);
  451.     }
  452.     return code;
  453. }
  454.  
  455. /* Allocate a resource, but don't open the stream. */
  456. int
  457. pdf_alloc_resource(gx_device_pdf * pdev, pdf_resource_type_t rtype, gs_id rid,
  458.            pdf_resource_t ** ppres, long id)
  459. {
  460.     int code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, rid),
  461.                    resource_structs[rtype], ppres, id);
  462.  
  463.     if (code >= 0)
  464.     (*ppres)->rid = rid;
  465.     return code;
  466. }
  467.  
  468. /* Get the object id of a resource. */
  469. long
  470. pdf_resource_id(const pdf_resource_t *pres)
  471. {
  472.     return pres->object->id;
  473. }
  474.  
  475. /* End an aside or other separate object. */
  476. int
  477. pdf_end_separate(gx_device_pdf * pdev)
  478. {
  479.     int code = pdf_end_obj(pdev);
  480.  
  481.     pdev->strm = pdev->asides.save_strm;
  482.     pdev->asides.save_strm = 0;
  483.     return code;
  484. }
  485. int
  486. pdf_end_aside(gx_device_pdf * pdev)
  487. {
  488.     return pdf_end_separate(pdev);
  489. }
  490.  
  491. /* End a resource. */
  492. int
  493. pdf_end_resource(gx_device_pdf * pdev)
  494. {
  495.     return pdf_end_aside(pdev);
  496. }
  497.  
  498. /* Copy data from a temporary file to a stream. */
  499. void
  500. pdf_copy_data(stream *s, FILE *file, long count)
  501. {
  502.     long left = count;
  503.     byte buf[sbuf_size];
  504.  
  505.     while (left > 0) {
  506.     uint copy = min(left, sbuf_size);
  507.  
  508.     fread(buf, 1, sbuf_size, file);
  509.     pwrite(s, buf, copy);
  510.     left -= copy;
  511.     }
  512. }
  513.  
  514. /* ------ Pages ------ */
  515.  
  516. /* Get or assign the ID for a page. */
  517. /* Returns 0 if the page number is out of range. */
  518. long
  519. pdf_page_id(gx_device_pdf * pdev, int page_num)
  520. {
  521.     cos_dict_t *Page;
  522.  
  523.     if (page_num < 1)
  524.     return 0;
  525.     if (page_num >= pdev->num_pages) {    /* Grow the pages array. */
  526.     uint new_num_pages =
  527.         max(page_num + 10, pdev->num_pages << 1);
  528.     pdf_page_t *new_pages =
  529.         gs_resize_object(pdev->pdf_memory, pdev->pages, new_num_pages,
  530.                  "pdf_page_id(resize pages)");
  531.  
  532.     if (new_pages == 0)
  533.         return 0;
  534.     memset(&new_pages[pdev->num_pages], 0,
  535.            (new_num_pages - pdev->num_pages) * sizeof(pdf_page_t));
  536.     pdev->pages = new_pages;
  537.     pdev->num_pages = new_num_pages;
  538.     }
  539.     if ((Page = pdev->pages[page_num - 1].Page) == 0) {
  540.     pdev->pages[page_num - 1].Page = Page =
  541.         cos_dict_alloc(pdev, "pdf_page_id");
  542.     Page->id = pdf_obj_ref(pdev);
  543.     }
  544.     return Page->id;
  545. }
  546.  
  547. /* Get the page structure for the current page. */
  548. pdf_page_t *
  549. pdf_current_page(gx_device_pdf *pdev)
  550. {
  551.     return &pdev->pages[pdev->next_page];
  552. }
  553.  
  554. /* Get the dictionary object for the current page. */
  555. cos_dict_t *
  556. pdf_current_page_dict(gx_device_pdf *pdev)
  557. {
  558.     if (pdf_page_id(pdev, pdev->next_page + 1) <= 0)
  559.     return 0;
  560.     return pdev->pages[pdev->next_page].Page;
  561. }
  562.  
  563. /* Write saved page- or document-level information. */
  564. int
  565. pdf_write_saved_string(gx_device_pdf * pdev, gs_string * pstr)
  566. {
  567.     if (pstr->data != 0) {
  568.     pwrite(pdev->strm, pstr->data, pstr->size);
  569.     gs_free_string(pdev->pdf_memory, pstr->data, pstr->size,
  570.                "pdf_write_saved_string");
  571.     pstr->data = 0;
  572.     }
  573.     return 0;
  574. }
  575.  
  576. /* Open a page for writing. */
  577. int
  578. pdf_open_page(gx_device_pdf * pdev, pdf_context_t context)
  579. {
  580.     if (!is_in_page(pdev)) {
  581.     if (pdf_page_id(pdev, pdev->next_page + 1) == 0)
  582.         return_error(gs_error_VMerror);
  583.     pdf_open_document(pdev);
  584.     }
  585.     /* Note that context may be PDF_IN_NONE here. */
  586.     return pdf_open_contents(pdev, context);
  587. }
  588.  
  589. /* ------ Miscellaneous output ------ */
  590.  
  591. /* Generate the default Producer string. */
  592. void
  593. pdf_store_default_Producer(char buf[PDF_MAX_PRODUCER])
  594. {
  595.     sprintf(buf, ((gs_revision % 100) == 0 ? "(%s %1.1f)" : "(%s %1.2f)"),
  596.         gs_product, gs_revision / 100.0);
  597. }
  598.  
  599. /* Write matrix values. */
  600. void
  601. pdf_put_matrix(gx_device_pdf * pdev, const char *before,
  602.            const gs_matrix * pmat, const char *after)
  603. {
  604.     stream *s = pdev->strm;
  605.  
  606.     if (before)
  607.     pputs(s, before);
  608.     pprintg6(s, "%g %g %g %g %g %g ",
  609.          pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
  610.     if (after)
  611.     pputs(s, after);
  612. }
  613.  
  614. /*
  615.  * Write a name, with escapes for unusual characters.  In PDF 1.1, we have
  616.  * no choice but to replace these characters with '?'; in PDF 1.2, we can
  617.  * use an escape sequence for anything except a null <00>.
  618.  */
  619. void
  620. pdf_put_name_escaped(stream *s, const byte *nstr, uint size, bool escape)
  621. {
  622.     uint i;
  623.  
  624.     pputc(s, '/');
  625.     for (i = 0; i < size; ++i) {
  626.     uint c = nstr[i];
  627.     char hex[4];
  628.  
  629.     switch (c) {
  630.         case '#':
  631.         /* These are valid in 1.1, but must be escaped in 1.2. */
  632.         if (escape) {
  633.             sprintf(hex, "#%02x", c);
  634.             pputs(s, hex);
  635.             break;
  636.         }
  637.         /* falls through */
  638.         default:
  639.         if (c >= 0x21 && c <= 0x7e) {
  640.             /* These are always valid. */
  641.             pputc(s, c);
  642.             break;
  643.         }
  644.         /* falls through */
  645.         case '%':
  646.         case '(': case ')':
  647.         case '<': case '>':
  648.         case '[': case ']':
  649.         case '{': case '}':
  650.         case '/':
  651.         /* These characters are invalid in both 1.1 and 1.2, */
  652.         /* but can be escaped in 1.2. */
  653.         if (escape) {
  654.             sprintf(hex, "#%02x", c);
  655.             pputs(s, hex);
  656.             break;
  657.         }
  658.         /* falls through */
  659.         case 0:
  660.         /* This is invalid in 1.1 and 1.2, and cannot be escaped. */
  661.         pputc(s, '?');
  662.     }
  663.     }
  664. }
  665. void
  666. pdf_put_name(const gx_device_pdf *pdev, const byte *nstr, uint size)
  667. {
  668.     pdf_put_name_escaped(pdev->strm, nstr, size,
  669.              pdev->CompatibilityLevel >= 1.2);
  670. }
  671.  
  672. /*
  673.  * Write a string in its shortest form ( () or <> ).  Note that
  674.  * this form is different depending on whether binary data are allowed.
  675.  * We wish PDF supported ASCII85 strings ( <~ ~> ), but it doesn't.
  676.  */
  677. void
  678. pdf_put_string(const gx_device_pdf * pdev, const byte * str, uint size)
  679. {
  680.     psdf_write_string(pdev->strm, str, size,
  681.               (pdev->binary_ok ? PRINT_BINARY_OK : 0));
  682. }
  683.  
  684. /* Write a value, treating names specially. */
  685. void
  686. pdf_write_value(const gx_device_pdf * pdev, const byte * vstr, uint size)
  687. {
  688.     if (size > 0 && vstr[0] == '/')
  689.     pdf_put_name(pdev, vstr + 1, size - 1);
  690.     else
  691.     pwrite(pdev->strm, vstr, size);
  692. }
  693.  
  694. /* Store filters for a stream. */
  695. /* Currently this only saves parameters for CCITTFaxDecode. */
  696. int
  697. pdf_put_filters(cos_dict_t *pcd, gx_device_pdf *pdev, stream *s,
  698.         const pdf_filter_names_t *pfn)
  699. {
  700.     const char *filter_name = 0;
  701.     bool binary_ok = true;
  702.     stream *fs = s;
  703.     cos_dict_t *decode_parms = 0;
  704.     int code;
  705.  
  706.     for (; fs != 0; fs = fs->strm) {
  707.     const stream_state *st = fs->state;
  708.     const stream_template *template = st->template;
  709.  
  710. #define TEMPLATE_IS(atemp)\
  711.   (template->process == (atemp).process)
  712.     if (TEMPLATE_IS(s_A85E_template))
  713.         binary_ok = false;
  714.     else if (TEMPLATE_IS(s_CFE_template)) {
  715.         cos_param_list_writer_t writer;
  716.         stream_CF_state cfs;
  717.  
  718.         decode_parms =
  719.         cos_dict_alloc(pdev, "pdf_put_image_filters(decode_parms)");
  720.         if (decode_parms == 0)
  721.         return_error(gs_error_VMerror);
  722.         CHECK(cos_param_list_writer_init(&writer, decode_parms, 0));
  723.         /*
  724.          * If EndOfBlock is true, we mustn't write out a Rows value.
  725.          * This is a hack....
  726.          */
  727.         cfs = *(const stream_CF_state *)st;
  728.         if (cfs.EndOfBlock)
  729.         cfs.Rows = 0;
  730.         CHECK(s_CF_get_params((gs_param_list *)&writer, &cfs, false));
  731.         filter_name = pfn->CCITTFaxDecode;
  732.     } else if (TEMPLATE_IS(s_DCTE_template))
  733.         filter_name = pfn->DCTDecode;
  734.     else if (TEMPLATE_IS(s_zlibE_template))
  735.         filter_name = pfn->FlateDecode;
  736.     else if (TEMPLATE_IS(s_LZWE_template))
  737.         filter_name = pfn->LZWDecode;
  738.     else if (TEMPLATE_IS(s_PNGPE_template)) {
  739.         /* This is a predictor for FlateDecode or LZWEncode. */
  740.         const stream_PNGP_state *const ss =
  741.         (const stream_PNGP_state *)st;
  742.  
  743.         decode_parms =
  744.         cos_dict_alloc(pdev, "pdf_put_image_filters(decode_parms)");
  745.         if (decode_parms == 0)
  746.         return_error(gs_error_VMerror);
  747.         CHECK(cos_dict_put_c_key_int(decode_parms, "/Predictor",
  748.                      ss->Predictor));
  749.         CHECK(cos_dict_put_c_key_int(decode_parms, "/Columns",
  750.                      ss->Columns));
  751.         if (ss->Colors != 1)
  752.         CHECK(cos_dict_put_c_key_int(decode_parms, "/Colors",
  753.                          ss->Colors));
  754.         if (ss->BitsPerComponent != 8)
  755.         CHECK(cos_dict_put_c_key_int(decode_parms,
  756.                          "/BitsPerComponent",
  757.                          ss->BitsPerComponent));
  758.     } else if (TEMPLATE_IS(s_RLE_template))
  759.         filter_name = pfn->RunLengthDecode;
  760. #undef TEMPLATE_IS
  761.     }
  762.     if (filter_name) {
  763.     if (binary_ok) {
  764.         CHECK(cos_dict_put_c_strings(pcd, pfn->Filter, filter_name));
  765.         if (decode_parms)
  766.         CHECK(cos_dict_put_c_key_object(pcd, pfn->DecodeParms,
  767.                         COS_OBJECT(decode_parms)));
  768.     } else {
  769.         cos_array_t *pca =
  770.         cos_array_alloc(pdev, "pdf_put_image_filters(Filters)");
  771.  
  772.         if (pca == 0)
  773.         return_error(gs_error_VMerror);
  774.         CHECK(cos_array_add_c_string(pca, pfn->ASCII85Decode));
  775.         CHECK(cos_array_add_c_string(pca, filter_name));
  776.         CHECK(cos_dict_put_c_key_object(pcd, pfn->Filter,
  777.                         COS_OBJECT(pca)));
  778.         if (decode_parms) {
  779.         pca = cos_array_alloc(pdev,
  780.                       "pdf_put_image_filters(DecodeParms)");
  781.         if (pca == 0)
  782.             return_error(gs_error_VMerror);
  783.         CHECK(cos_array_add_c_string(pca, "null"));
  784.         CHECK(cos_array_add_object(pca, COS_OBJECT(decode_parms)));
  785.         CHECK(cos_dict_put_c_key_object(pcd, pfn->DecodeParms,
  786.                         COS_OBJECT(pca)));
  787.         }
  788.     }
  789.     } else if (!binary_ok)
  790.     CHECK(cos_dict_put_c_strings(pcd, pfn->Filter, pfn->ASCII85Decode));
  791.     return 0;
  792. }
  793.  
  794. /* Add a Flate compression filter to a binary writer. */
  795. private int
  796. pdf_flate_binary(gx_device_pdf *pdev, psdf_binary_writer *pbw)
  797. {
  798.     const stream_template *template = &s_zlibE_template;
  799.     stream_state *st = s_alloc_state(pdev->pdf_memory, template->stype,
  800.                      "pdf_write_function");
  801.  
  802.     if (st == 0)
  803.     return_error(gs_error_VMerror);
  804.     if (template->set_defaults)
  805.     template->set_defaults(st);
  806.     return psdf_encode_binary(pbw, template, st);
  807. }
  808.  
  809. /*
  810.  * Begin a Function or halftone data stream.  The client has opened the
  811.  * object and written the << and any desired dictionary keys.
  812.  */
  813. int
  814. pdf_begin_data(gx_device_pdf *pdev, pdf_data_writer_t *pdw)
  815. {
  816.     long length_id = pdf_obj_ref(pdev);
  817.     stream *s = pdev->strm;
  818. #define USE_ASCII85 1
  819. #define USE_FLATE 2
  820.     static const char *const fnames[4] = {
  821.     "", "/Filter/ASCII85Decode", "/Filter/FlateDecode",
  822.     "/Filter[/ASCII85Decode/FlateDecode]"
  823.     };
  824.     int filters = 0;
  825.     int code;
  826.  
  827.     if (!pdev->binary_ok)
  828.     filters |= USE_ASCII85;
  829.     if (pdev->CompatibilityLevel >= 1.2)
  830.     filters |= USE_FLATE;
  831.     pputs(s, fnames[filters]);
  832.     pprintld1(s, "/Length %ld 0 R>>stream\n", length_id);
  833.     code = psdf_begin_binary((gx_device_psdf *)pdev, &pdw->binary);
  834.     if (code < 0)
  835.     return code;
  836.     pdw->start = stell(s);
  837.     pdw->length_id = length_id;
  838.     if (filters & USE_FLATE)
  839.     code = pdf_flate_binary(pdev, &pdw->binary);
  840.     return code;
  841. #undef USE_ASCII85
  842. #undef USE_FLATE
  843. }
  844.  
  845. /* End a data stream. */
  846. int
  847. pdf_end_data(pdf_data_writer_t *pdw)
  848. {
  849.     gx_device_pdf *pdev = (gx_device_pdf *)pdw->binary.dev;
  850.     int code = psdf_end_binary(&pdw->binary);
  851.     long length = stell(pdev->strm) - pdw->start;
  852.  
  853.     if (code < 0)
  854.     return code;
  855.     pputs(pdev->strm, "\nendstream\n");
  856.     pdf_end_separate(pdev);
  857.     pdf_open_separate(pdev, pdw->length_id);
  858.     pprintld1(pdev->strm, "%ld\n", length);
  859.     return pdf_end_separate(pdev);
  860. }
  861.  
  862. /* Create a Function object. */
  863. int
  864. pdf_function(gx_device_pdf *pdev, const gs_function_t *pfn,
  865.          cos_value_t *pvalue)
  866. {
  867.     gs_function_info_t info;
  868.     cos_param_list_writer_t rlist;
  869.     pdf_resource_t *pres;
  870.     cos_object_t *pcfn;
  871.     cos_dict_t *pcd;
  872.     cos_value_t v;
  873.     int code = pdf_alloc_resource(pdev, resourceFunction, gs_no_id, &pres, 0L);
  874.  
  875.     if (code < 0)
  876.     return code;
  877.     pcfn = pres->object;
  878.     gs_function_get_info(pfn, &info);
  879.     if (info.DataSource != 0) {
  880.     psdf_binary_writer writer;
  881.     stream *save = pdev->strm;
  882.     cos_stream_t *pcos;
  883.     stream *s;
  884.  
  885.     cos_become(pcfn, cos_type_stream);
  886.     pcos = (cos_stream_t *)pcfn;
  887.     pcd = cos_stream_dict(pcos);
  888.     s = cos_write_stream_alloc(pcos, pdev, "pdf_function");
  889.     if (s == 0)
  890.         return_error(gs_error_VMerror);
  891.     pdev->strm = s;
  892.     code = psdf_begin_binary((gx_device_psdf *)pdev, &writer);
  893.     if (code >= 0 && info.data_size > 30 &&    /* 30 is arbitrary */
  894.         pdev->CompatibilityLevel >= 1.2
  895.         )
  896.         code = pdf_flate_binary(pdev, &writer);
  897.     if (code >= 0) {
  898.         static const pdf_filter_names_t fnames = {
  899.         PDF_FILTER_NAMES
  900.         };
  901.  
  902.         code = pdf_put_filters(pcd, pdev, writer.strm, &fnames);
  903.     }
  904.     if (code >= 0) {
  905.         byte buf[100];        /* arbitrary */
  906.         ulong pos;
  907.         uint count;
  908.         const byte *ptr;
  909.  
  910.         for (pos = 0; pos < info.data_size; pos += count) {
  911.         count = min(sizeof(buf), info.data_size - pos);
  912.         data_source_access_only(info.DataSource, pos, count, buf,
  913.                     &ptr);
  914.         pwrite(writer.strm, ptr, count);
  915.         }
  916.         code = psdf_end_binary(&writer);
  917.         sclose(s);
  918.     }
  919.     pdev->strm = save;
  920.     if (code < 0)
  921.         return code;
  922.     } else {
  923.     cos_become(pcfn, cos_type_dict);
  924.     pcd = (cos_dict_t *)pcfn;
  925.     }
  926.     if (info.Functions != 0) {
  927.     int i;
  928.     cos_array_t *functions =
  929.         cos_array_alloc(pdev, "pdf_function(Functions)");
  930.  
  931.     if (functions == 0)
  932.         return_error(gs_error_VMerror);
  933.     for (i = 0; i < info.num_Functions; ++i) {
  934.         if ((code = pdf_function(pdev, info.Functions[i], &v)) < 0 ||
  935.         (code = cos_array_add(functions, &v)) < 0
  936.         ) {
  937.         COS_FREE(functions, "pdf_function(Functions)");
  938.         return code;
  939.         }
  940.     }
  941.     code = cos_dict_put_c_key(pcd, "/Functions",
  942.                   COS_OBJECT_VALUE(&v, functions));
  943.     if (code < 0) {
  944.         COS_FREE(functions, "pdf_function(Functions)");
  945.         return code;
  946.     }
  947.     }
  948.     code = cos_param_list_writer_init(&rlist, pcd, PRINT_BINARY_OK);
  949.     if (code < 0)
  950.     return code;
  951.     code = gs_function_get_params(pfn, (gs_param_list *)&rlist);
  952.     if (code < 0)
  953.     return code;
  954.     COS_OBJECT_VALUE(pvalue, pcd);
  955.     return 0;
  956. }
  957.  
  958. /* Write a Function object. */
  959. int
  960. pdf_write_function(gx_device_pdf *pdev, const gs_function_t *pfn, long *pid)
  961. {
  962.     cos_value_t value;
  963.     int code = pdf_function(pdev, pfn, &value);
  964.  
  965.     if (code < 0)
  966.     return code;
  967.     *pid = value.contents.object->id;
  968.     return 0;
  969. }
  970.